using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace BindingFlagsSnippet
{
    public enum Color
    {
        Red = 0,
        Yellow = 1,
        Blue = 2,
        Orange = 3,
        None = 4
    }

    public class BaseClass { }
    public interface BaseInterFace { }
    public class MyClass<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11>
        where T1 : struct
        where T2 : class
        where T3 : notnull
        where T4 : unmanaged
        where T5 : new()
        where T6 : BaseClass
        where T7 : BaseInterFace
        where T8 : T2
        // 组合条件
        where T9 : class, new()
        where T10 : BaseClass, BaseInterFace, new()
    {
    }

    class Example
    {
        // 解析一个泛型类型，并且解析约束
        public static string GetGenericString(Type type)
        {
            if (!type.IsGenericType)
                return type.Name;

            string className = type.Name.Split("`")[0] + "<";
            Type[] types = ((System.Reflection.TypeInfo)type).GenericTypeParameters;
            for (int i = 0; i < types.Length; i++)
            {
                className += types[i].Name;
                if (i + 1 < types.Length)
                    className += ",";
            }

            className += "> ";

            foreach (var item in types)
            {
                string str = "where ";
                str += item.Name + " : ";

                Type[] genericTypes = item.GetGenericParameterConstraints();
                GenericParameterAttributes genricAttrs = item.GenericParameterAttributes;

                int length = genericTypes.Length - 1;
                // 不具有任何约束
                if (genericTypes.Length == 0 && genricAttrs == GenericParameterAttributes.None && item.GetCustomAttributes().ToArray().Length == 0)
                    str = String.Empty;

                // 只有一种约束的情况下
                // 符号条件有 staruct、unmanaged、<基类名>、<接口名>、T:U
                else if (genericTypes.Length == 1)
                    str += GetGenericType(genericTypes[0]).Item1;

                // 没有 Type 约束时
                else if (genericTypes.Length == 0)
                    str += GetGenericType(genricAttrs).Item1;

                // 类型约束和特殊标识约束一起时，最麻烦了
                // 他们有组合关系，又有顺序关系
                // 分为三个顺序阶段，黄色，蓝色，橙
                else
                {
                    List<string> color = new List<string>();


                    // 黄色
                    bool a = IsHasYellow(genericTypes);
                    bool b = IsHasYellow(genricAttrs);
                    if (a == true)
                        color.Add(genericTypes.FirstOrDefault(x => !x.IsInterface && x.IsSubclassOf(typeof(System.Object))).Name);
                    else if (b == true)
                        color.Add(GetGenericType(genricAttrs).Item1);
                    else color.Add(string.Empty);

                    // 蓝色
                    color.Add(GetGenericType(genericTypes.Where(x => !(!x.IsInterface && x.IsSubclassOf(typeof(System.Object)))).ToArray()));

                    // 橙色
                    if (genricAttrs.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                        color.Add(GetGenericType(genricAttrs).Item1);

                    str += string.Join(",", color.ToArray());
                }

                className += str + " ";
            }
            return className;
        }
        // 枚举值为 8,16 时
        // 判断是 struct 还是 unamaged
        // 红色
        public static string GetStructUnmanaged(Type type)
        {
            if (type.IsSecurityCritical)
                return "struct";
            return "unmanaged";
        }

        // 枚举值为 4 时
        // 黄色
        public static string GetClass()
        {
            return "class";
        }

        /// <summary>
        /// 判断是否有黄色
        /// </summary>
        /// <returns></returns>
        public static bool IsHasYellow(Type[] types)
        {
            return types.Any(x => !x.IsInterface && x.IsSubclassOf(typeof(System.Object)));
        }

        /// <summary>
        /// 判断是否有黄色
        /// </summary>
        /// <returns></returns>
        public static bool IsHasYellow(GenericParameterAttributes attributes)
        {
            return
                attributes == GenericParameterAttributes.ReferenceTypeConstraint ||
                attributes == GenericParameterAttributes.None ?
                true : false;
        }

        /// <summary>
        /// struct,<基类>,<接口>，T:U
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static (string, Color) GetGenericType(Type type)
        {
            // 约束也可以是泛型，这里不做处理
            if (type.Name == "ValueType")
                return ("struct", Color.Red);
            else if (type.IsInterface)
                return (type.Name, Color.Blue);
            else if (type.IsSubclassOf(typeof(Object)))
            {
                return (type.Name, Color.Yellow);
            }
            else
                return (type.Name, Color.Blue);
        }

        /// <summary>
        /// 多种组合条件,struct,<基类>,<接口>，T:U
        /// </summary>
        /// <param name="types"></param>
        /// <returns></returns>
        public static string GetGenericType(Type[] types)
        {
            int length = types.Length - 1;
            string str = "";
            for (int i = 0; i <= length; i++)
            {
                // 约束也可以是泛型，这里不做处理
                if (types[i].Name == "ValueType")
                    str += "struct";
                else
                    str += types[i].Name;

                if (i < length)
                    str += ",";
            }
            return str;
        }

        /// <summary>
        /// 单个或多个组合条件, class、notnull、new()
        /// </summary>
        /// <param name="attributes"></param>
        /// <returns></returns>
        public static (string, Color) GetGenericType(GenericParameterAttributes attributes)
        {
            /*
             * 下面是不同约束的结果
             * class：ReferenceTypeConstraint
             * notnull：None
             * unmanaged：NotNullableValueTypeConstraint, DefaultConstructorConstraint
             * new()：DefaultConstructorConstraint
             */
            switch (attributes)
            {
                case GenericParameterAttributes.ReferenceTypeConstraint:
                    return ("class", Color.Yellow);
                case GenericParameterAttributes.None:
                    return ("notnull", Color.Yellow);
                case GenericParameterAttributes.DefaultConstructorConstraint:
                    return ("new()", Color.Orange);
                // 多种组合条件时
                default:
                    string str = "";
                    if (attributes.HasFlag(GenericParameterAttributes.ReferenceTypeConstraint))
                        str += "class,";
                    if (attributes.HasFlag(GenericParameterAttributes.None))
                        str += "notnull,";
                    if (attributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint))
                        str += "new(),";
                    // 去除最后一个 , 号，
                    return (str.Substring(0, str.Length - 1), Color.None);
            }
        }

        static void Main()
        {
            Type type = typeof(MyClass<,,,,,,,,,,>);
            Console.WriteLine(GetGenericString(type));

            Console.ReadKey();
        }
    }
}
